home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mntlib43 / mntlib / scanf.c < prev    next >
C/C++ Source or Header  |  1994-02-14  |  10KB  |  548 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <string.h>
  4. #include <stdarg.h>
  5. #include "lib.h"
  6.  
  7. /*
  8.  * %efg were loosing big time
  9.  *    fixed  ++jrb
  10.  * all floating conversion now done by atof. much is gained by this.
  11.  *    ++jrb
  12.  *
  13.  * hacked to use stdarg by bm
  14.  */
  15.  
  16. #ifndef __NO_FLOAT__
  17. #define FLOATS 1
  18. #endif
  19.  
  20. #ifndef TRUE
  21. #define TRUE  1
  22. #define FALSE 0
  23. #endif
  24.  
  25. #define    skip() \
  26.   while (isspace(c)) { charcnt++; c = (*get)(ip); if (c == EOF) goto done; }
  27. #define TEN_MUL(X)    ((((X) << 2) + (X)) << 1)
  28.  
  29. #if FLOATS
  30. /* fp scan actions */
  31. #define F_NADA    0    /* just change state */
  32. #define F_SIGN    1    /* set sign */
  33. #define F_ESIGN    2    /* set exponent's sign */
  34. #define F_INT    3    /* adjust integer part */
  35. #define F_FRAC    4    /* adjust fraction part */
  36. #define F_EXP    5    /* adjust exponent part */
  37. #define F_QUIT    6
  38.  
  39. #define NSTATE    8
  40. #define FS_INIT        0    /* initial state */
  41. #define FS_SIGNED    1    /* saw sign */
  42. #define FS_DIGS        2    /* saw digits, no . */
  43. #define FS_DOT        3    /* saw ., no digits */
  44. #define FS_DD        4    /* saw digits and . */
  45. #define FS_E        5    /* saw 'e' */
  46. #define FS_ESIGN    6    /* saw exp's sign */
  47. #define FS_EDIGS    7    /* saw exp's digits */
  48.  
  49. #define FC_DIG        0
  50. #define FC_DOT        1
  51. #define FC_E        2
  52. #define FC_SIGN        3
  53.  
  54. /* given transition,state do what action? */
  55. static const int fp_do[][NSTATE] = {
  56. {F_INT,F_INT,F_INT,
  57.      F_FRAC,F_FRAC,
  58.      F_EXP,F_EXP,F_EXP},    /* see digit */
  59. {F_NADA,F_NADA,F_NADA,
  60.      F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT},    /* see '.' */
  61. {F_QUIT,F_QUIT,
  62.      F_NADA,F_QUIT,F_NADA,
  63.      F_QUIT,F_QUIT,F_QUIT},    /* see e/E */
  64. {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
  65.      F_ESIGN,F_QUIT,F_QUIT},    /* see sign */
  66. };
  67. /* given transition,state what is new state? */
  68. static const int fp_ns[][NSTATE] = {
  69. {FS_DIGS,FS_DIGS,FS_DIGS,
  70.      FS_DD,FS_DD,
  71.      FS_EDIGS,FS_EDIGS,FS_EDIGS},    /* see digit */
  72. {FS_DOT,FS_DOT,FS_DD,
  73.  },    /* see '.' */
  74. {0,0,
  75.      FS_E,0,FS_E,
  76.  },    /* see e/E */
  77. {FS_SIGNED,0,0,0,0,
  78.      FS_ESIGN,0,0},    /* see sign */
  79. };
  80. /* which states are valid terminators? */
  81. static const int fp_sval[NSTATE] = {
  82.     0,0,1,0,1,1,1,1
  83. };
  84. #endif
  85.  
  86. #ifdef __STDC__
  87. int _scanf(register FILE *ip, int (*get)(FILE *),
  88.  int (*unget)(int, FILE *), const char *_fmt, va_list args)
  89. #else
  90. int
  91. _scanf(ip, get, unget, _fmt, args)
  92. FILE *ip;
  93. int (*get) __PROTO((FILE *));
  94. int (*unget) __PROTO((int, FILE *));
  95. const char *_fmt;
  96. char **args;
  97. #endif
  98. {
  99.     register long n;
  100.     register int c, width, lval, sval, cnt = 0, charcnt = 1;
  101. #if defined (PRINTF_LONGLONG) || defined (__STDC__)
  102.     register int llval = 0;
  103. #endif
  104. #ifdef PRINTF_LONGLONG
  105.     register long long lln;
  106. #endif
  107.     int store, neg, base, endnull, c2;
  108.     register unsigned char *p = 0;
  109.     const unsigned char *fmt = (const unsigned char *) _fmt;
  110.     char delim[256], *q;
  111. #if FLOATS
  112.     double fx;
  113.     char fbuf[128], *fbp;
  114.     int fstate, trans;
  115.     extern double atof __PROTO((const char *));
  116. #endif
  117.  
  118.     c = (*get)(ip);
  119.     while (*fmt)
  120.     {
  121.     if (*fmt == '%')
  122.     {
  123.         width    = -1;
  124.         lval    = FALSE;
  125. #if defined (PRINTF_LONGLONG) || defined (__STDC__)
  126.         llval    = FALSE;
  127. #endif
  128.         sval    = FALSE;
  129.         store    = TRUE;
  130.  
  131.         if (*++fmt == '*')
  132.         {
  133.         store = FALSE;
  134.         ++fmt;
  135.         }
  136.  
  137.         if (isdigit (*fmt))        /* width digit(s) */
  138.           {
  139.         width = *fmt++ - '0';
  140.         while (isdigit (*fmt))
  141.           width = TEN_MUL (width) + *fmt++ - '0';
  142.           }
  143.  
  144.       fmtnxt:
  145.         switch(*fmt++)
  146.         {
  147.           case 'l':    /* long data */
  148. #ifdef PRINTF_LONGLONG
  149.         if (lval)
  150.             llval = TRUE;
  151. #endif
  152.         lval = TRUE;
  153.         goto fmtnxt;
  154.  
  155. #ifdef __STDC__
  156.           case 'L': /* long double */
  157.         llval = TRUE;
  158.         goto fmtnxt;
  159. #endif
  160.  
  161.           case 'h':    /* short data (for compatibility) */
  162.         sval = TRUE;
  163.         goto fmtnxt;
  164.  
  165.           case 'i':    /* any-base numeric */
  166.         base = 0;
  167.         neg = -1;
  168.         goto numfmt;
  169.  
  170.           case 'b':    /* unsigned binary, non-standard */
  171.           case 'B': /* non-standard */
  172.         base = 2;
  173.         neg = 0;
  174.         goto numfmt;
  175.  
  176.           case 'o':    /* unsigned octal */
  177.           case 'O': /* non-standard */
  178.         base = 8;
  179.         neg = 0;
  180.         goto numfmt;
  181.  
  182.           case 'p': /* pointer */
  183.         lval = TRUE;
  184. #ifdef PRINTF_LONGLONG
  185.         llval = FALSE;
  186. #endif
  187.         /* fall through */
  188.  
  189.           case 'x':    /* unsigned hexadecimal */
  190.           case 'X': /* non-standard */
  191.         base = 16;
  192.         neg = 0;
  193.         goto numfmt;
  194.  
  195.           case 'd':    /* SIGNED decimal */
  196.           case 'D': /* non-standard */
  197.         base = 10;
  198.         neg = -1;
  199.         goto numfmt;
  200.  
  201.           case 'u':    /* unsigned decimal */
  202.           case 'U': /* non-standard */
  203.         base = 10;
  204.         neg = 0;
  205.           numfmt:
  206.         skip();
  207.         memset (delim, -1, sizeof (delim));
  208.         if (isupper(fmt[-1])) {
  209.             /* non-standard */
  210. #ifdef PRINTF_LONGLONG
  211.             if (lval) llval = TRUE;
  212. #endif
  213.             lval = TRUE;
  214.         }
  215.         n = 0;
  216. #ifdef PRINTF_LONGLONG
  217.         lln = 0;
  218. #endif
  219.         if (width == 0)
  220.           goto savnum;
  221.         if (!base)
  222.         {
  223.             if (c == '%') /* non-standard */
  224.             {
  225.             base = 2;
  226.             neg = 0;
  227.             goto skip1;
  228.             }
  229.             else if (c == '0')
  230.             {
  231.             if (--width == 0)
  232.               goto savnum;
  233.             charcnt++;
  234.             c = (*get)(ip);
  235.             if (c == EOF)
  236.                 goto savnum;
  237.             if ((c != 'x')
  238.                 && (c != 'X'))
  239.             {
  240.                 base = 8;
  241.                 neg = 0;
  242.                 for (c2 = 0; c2 < 8; c2++)
  243.                   delim[c2 + '0'] = c2;
  244.                 goto zeroin;
  245.             }
  246.             base = 16;
  247.             neg = 0;
  248.             goto skip1;
  249.             }
  250.             else
  251.               base = 10;
  252.         }
  253.  
  254.         /* Check for 0x prefix */
  255.         if (base == 16 && c == '0')
  256.           {
  257.             if (--width == 0)
  258.               goto savnum;
  259.             charcnt++;
  260.             c = (*get) (ip);
  261.             if (c == EOF)
  262.               goto done;
  263.             if (c == 'x' || c == 'X')
  264.               goto skip1;
  265.           }
  266.         else if (neg == -1)
  267.           {
  268.             neg = c == '-';
  269.             if (neg || c == '+')
  270.               {
  271.               skip1:
  272.             if (--width == 0)
  273.               goto done;
  274.             charcnt++;
  275.             c = (*get)(ip);
  276.             if (c == EOF)
  277.               goto done;
  278.               }
  279.           }
  280.  
  281.         /* delim[c] -> value of c or -1 */
  282.         p = (unsigned char *) "FEDCBAfedcba9876543210";
  283.         q = "\17\16\15\14\13\12\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0";
  284.         if (base < 16)
  285.           {
  286.             /* skip invalid digits */
  287.             p += 22 - base;
  288.             q += 22 - base;
  289.           }
  290.         while (*p)
  291.           delim[*p++] = *q++;
  292.  
  293.         if (delim[c] == (char) -1)
  294.           goto done;
  295.  
  296.         while (width--)
  297.         {
  298. #ifdef PRINTF_LONGLONG
  299.             if (llval)
  300.             lln = (lln * base) + delim[c];
  301.             else
  302. #endif
  303.             n = (n * base) + delim[c];
  304.             charcnt++;
  305.             c = (*get)(ip);
  306.             if (c == EOF)
  307.               break;
  308.           zeroin:
  309.             if (delim[c] == (char) -1)
  310.               break;
  311.         }
  312.           savnum:
  313.         if (store)
  314.         {
  315. #ifdef __STDC__
  316.             p = va_arg(args, void *);
  317. #else
  318.             p = ((unsigned char *) *args);
  319. #endif
  320. #ifdef PRINTF_LONGLONG
  321.             if (llval)
  322.             {
  323.             if (neg)
  324.                 lln=-lln;
  325.             *((long long*) p) = lln;
  326.             }
  327.             else
  328. #endif
  329.             {
  330.             if (neg)
  331.                 n = -n;
  332.             if (lval)
  333.                 *((long*) p) = n;
  334.             else if (sval)
  335.                 *((short *) p) = (short) n;
  336.             else
  337.                 *((int *) p) = (int) n;
  338.             ++cnt;
  339.             }
  340.         }
  341.         break;
  342.  
  343. #if FLOATS
  344.           case 'E': /* non-standard */
  345.           case 'F':
  346.           case 'G':
  347.         lval = TRUE;
  348.         /* fall through */
  349.  
  350.           case 'e':    /* float */
  351.           case 'f':
  352.           case 'g':
  353.         skip();
  354.  
  355.         memset (delim, -1, sizeof (delim));
  356.         for (c2 = '0'; c2 <= '9'; c2++)
  357.           delim[c2] = FC_DIG;
  358.         delim['.'] = FC_DOT;
  359.         delim['+'] = delim['-'] = FC_SIGN;
  360.         delim['e'] = delim['E'] = FC_E;
  361.  
  362.         fstate = FS_INIT;
  363.         fbp = fbuf;
  364.         while (c != EOF && width--) {
  365.             trans = delim[c];
  366.             if (trans == (char) -1)
  367.               break;
  368.             if (fbp - fbuf + 1 < sizeof (fbuf))
  369.               *fbp++ = c;
  370.  
  371.             if (fp_do[trans][fstate] == F_QUIT)
  372.             break;
  373.             fstate = fp_ns[trans][fstate];
  374.             charcnt++;
  375.             c = (*get)(ip);
  376.         }
  377.  
  378.         *fbp = '\0';
  379.         if (!fp_sval[fstate])
  380.             goto done;
  381.         if (store) {
  382.             fx = (*fbuf == '\0') ? 0.0 : atof(fbuf);
  383. #ifdef __STDC__
  384.             p = va_arg(args, void *);
  385. #else
  386.             p = (unsigned char *) *args;
  387. #endif
  388. #ifdef __STDC__
  389.             /* partial support for long double */
  390. #ifdef __M68881__   /* currently only with m68881 */
  391.             if (llval)
  392.               *(long double *) p = (long double) fx;
  393.             else
  394. #endif
  395. #endif
  396.             if (lval)
  397.             *((double *) p) = fx;
  398.             else
  399.             *((float *) p) = (float)fx;
  400.             ++cnt;
  401.         }
  402.         break;
  403. #endif
  404.  
  405.           case 'n':
  406.         if (store) {
  407. #ifdef __STDC__
  408.           p = va_arg(args, void *);
  409. #else
  410.           p = (unsigned char *) *args;
  411. #endif
  412.           /* Compensate for lookahead */
  413.           *((int *) p) = charcnt - 1;
  414.         }
  415.         break;
  416.  
  417.           case 'c':    /* character data */
  418.         if (width == -1)
  419.           width = 1;
  420.         endnull    = FALSE;
  421.         memset (delim, 0, sizeof (delim));
  422.         if (c == EOF)
  423.           goto done;
  424.         goto strproc;
  425.  
  426.           case '[':    /* string w/ delimiter set */
  427.         endnull    = TRUE;
  428.  
  429.         /* get delimiters */
  430.         neg = FALSE;
  431.         if (*fmt == '^')
  432.           {
  433.             fmt++;
  434.             neg = TRUE;
  435.           }
  436.  
  437.         memset (delim, !neg, sizeof (delim));
  438.  
  439.         if ((*fmt == ']') || (*fmt == '-'))
  440.         {
  441.             delim[*fmt++] = neg;
  442.         }
  443.  
  444.         while (c2 = *fmt++, c2 != ']')
  445.         {
  446.             if (c2 == '\0')
  447.               break;
  448.             if (*fmt == '-' && fmt[1] && fmt[1] != ']')
  449.               {
  450.             while (c2 <= fmt[1])
  451.               delim[c2++] = neg;
  452.             fmt += 2;
  453.               }
  454.             else
  455.               delim[c2] = neg;
  456.         }
  457.  
  458.         goto strproc;
  459.  
  460.           case 's':    /* string data */
  461.         skip();
  462.         memset (delim, 0, sizeof (delim));
  463.         delim['\t'] = 1;
  464.         delim['\n'] = 1;
  465.         delim['\v'] = 1;
  466.         delim['\f'] = 1;
  467.         delim['\r'] = 1;
  468.         delim[' '] = 1;
  469.         endnull    = TRUE;
  470.           strproc:
  471.         /* process string */
  472. #ifdef __STDC__
  473.         if (store)
  474.             p = va_arg(args, void *);
  475. #else
  476.         p = ((unsigned char *) *args);
  477. #endif
  478.  
  479.         /* if the 1st char fails, match fails */
  480.         if (width)
  481.         {
  482.             if (c == EOF || delim[c])
  483.             {
  484.             if (endnull)
  485.                 if (store)
  486.                     *p = '\0';
  487.             goto done;
  488.             }
  489.         }
  490.  
  491.         for (;;) /* FOREVER */
  492.         {
  493.             if (store)
  494.             *p++ = c;
  495.             charcnt++;
  496.             c = (*get)(ip);
  497.             if (c == EOF || --width == 0)
  498.             break;
  499.             if (delim[c])
  500.             break;
  501.         }
  502.  
  503.         if (store)
  504.         {
  505.             if (endnull)
  506.             *p = '\0';
  507.             ++cnt;
  508.         }
  509.         break;
  510.  
  511.           case '%':
  512.         --fmt;
  513.         goto cmatch;
  514.  
  515.           default:
  516.         goto done;
  517.         }
  518.     }
  519.     else if (isspace(*fmt))        /* skip whitespace */
  520.     {
  521.         fmt++;
  522.         skip();
  523.     }
  524.     else
  525.     {            /* normal match char */
  526.       cmatch:
  527.         if (c != *fmt++)
  528.           goto done;
  529.         charcnt++;
  530.         c = (*get)(ip);
  531.     }
  532.  
  533. #ifdef __STDC__
  534.     /* nothing to do */
  535. #else
  536.     if (store)
  537.         args++;
  538. #endif
  539.     }
  540.  
  541.   done:                        /* end of scan */
  542.     if (c != EOF)
  543.       (*unget) (c, ip);
  544.     if (c == EOF && cnt == 0)
  545.     return(EOF);
  546.     return(cnt);
  547. }
  548.